From 54b99d281b5aaeb40b230d18ee281b57e30d48fb Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Thu, 16 Apr 2020 01:36:13 -0400 Subject: [PATCH] Add a focus-within state This is used for widgets that contain the focus widget, reserving the focused state for the focus location itself. This aligns our focus state handling with https://www.w3.org/TR/selectors-4/ --- gtk/gtkcssselector.c | 1 + gtk/gtkcsstypes.c | 3 ++- gtk/gtkenums.h | 4 +++- gtk/gtkwidgetprivate.h | 2 +- gtk/gtkwindow.c | 12 +++++++++++- 5 files changed, 18 insertions(+), 4 deletions(-) diff --git a/gtk/gtkcssselector.c b/gtk/gtkcssselector.c index 5752005463..c7bc7bd7d5 100644 --- a/gtk/gtkcssselector.c +++ b/gtk/gtkcssselector.c @@ -1283,6 +1283,7 @@ gtk_css_selector_parse_selector_pseudo_class (GtkCssParser *parser, { "visited", GTK_STATE_FLAG_VISITED, }, { "checked", GTK_STATE_FLAG_CHECKED, }, { "focus-visible", GTK_STATE_FLAG_FOCUS_VISIBLE, }, + { "focus-within", GTK_STATE_FLAG_FOCUS_WITHIN, }, }; guint i; diff --git a/gtk/gtkcsstypes.c b/gtk/gtkcsstypes.c index 928b0f9a2a..ea83226317 100644 --- a/gtk/gtkcsstypes.c +++ b/gtk/gtkcsstypes.c @@ -232,7 +232,8 @@ gtk_css_pseudoclass_name (GtkStateFlags state) "visited", "checked", "drop(active)", - "focus-visible" + "focus-visible", + "focus-within" }; guint i; diff --git a/gtk/gtkenums.h b/gtk/gtkenums.h index 658be5f338..a7657a84ed 100644 --- a/gtk/gtkenums.h +++ b/gtk/gtkenums.h @@ -736,6 +736,7 @@ typedef enum * @GTK_STATE_FLAG_CHECKED: Widget is checked * @GTK_STATE_FLAG_DROP_ACTIVE: Widget is highlighted as a drop target for DND * @GTK_STATE_FLAG_FOCUS_VISIBLE: Widget has the visible focus + * @GTK_STATE_FLAG_FOCUS_WITHIN: Widget contains the keyboard focus * * Describes a widget state. Widget states are used to match the widget * against CSS pseudo-classes. Note that GTK extends the regular CSS @@ -757,7 +758,8 @@ typedef enum GTK_STATE_FLAG_VISITED = 1 << 10, GTK_STATE_FLAG_CHECKED = 1 << 11, GTK_STATE_FLAG_DROP_ACTIVE = 1 << 12, - GTK_STATE_FLAG_FOCUS_VISIBLE = 1 << 13 + GTK_STATE_FLAG_FOCUS_VISIBLE = 1 << 13, + GTK_STATE_FLAG_FOCUS_WITHIN = 1 << 14 } GtkStateFlags; /** diff --git a/gtk/gtkwidgetprivate.h b/gtk/gtkwidgetprivate.h index b2a4836ca0..1b104e77d9 100644 --- a/gtk/gtkwidgetprivate.h +++ b/gtk/gtkwidgetprivate.h @@ -45,7 +45,7 @@ typedef gboolean (*GtkSurfaceTransformChangedCallback) (GtkWidget const graphene_matrix_t *surface_transform, gpointer user_data); -#define GTK_STATE_FLAGS_BITS 14 +#define GTK_STATE_FLAGS_BITS 15 typedef struct _GtkWidgetSurfaceTransformData { diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c index 0451719907..3bd8d30e9f 100644 --- a/gtk/gtkwindow.c +++ b/gtk/gtkwindow.c @@ -5568,7 +5568,7 @@ synthesize_focus_change_events (GtkWindow *window, else ancestor = NULL; - flags = GTK_STATE_FLAG_FOCUSED; + flags = GTK_STATE_FLAG_FOCUSED | GTK_STATE_FLAG_FOCUS_WITHIN; if (gtk_window_get_focus_visible (GTK_WINDOW (window))) flags |= GTK_STATE_FLAG_FOCUS_VISIBLE; @@ -5612,8 +5612,14 @@ synthesize_focus_change_events (GtkWindow *window, gtk_widget_set_focus_child (widget, NULL); prev = widget; widget = gtk_widget_get_parent (widget); + + flags = flags & ~GTK_STATE_FLAG_FOCUSED; } + flags = GTK_STATE_FLAG_FOCUS_WITHIN; + if (gtk_window_get_focus_visible (GTK_WINDOW (window))) + flags |= GTK_STATE_FLAG_FOCUS_VISIBLE; + list = NULL; for (widget = new_focus; widget; widget = gtk_widget_get_parent (widget)) list = g_list_prepend (list, widget); @@ -5652,6 +5658,10 @@ synthesize_focus_change_events (GtkWindow *window, } check_crossing_invariants (widget, &crossing); gtk_widget_handle_crossing (widget, &crossing, 0, 0); + + if (l->next == NULL) + flags = flags | GTK_STATE_FLAG_FOCUSED; + gtk_widget_set_state_flags (widget, flags, FALSE); gtk_widget_set_focus_child (widget, focus_child); } -- 2.30.2